home *** CD-ROM | disk | FTP | other *** search
- /*
- * (C) 1992 SixxHeads Software
- * (C) 1992 Berkeley Systems Inc.
- *
- * This code is freely distributable, but credit must be given in any
- * derivative work.
- *
- * <Revision History>
- * 04/28/92 smz Created.
- * 05/16/92 smz insert the menus around the drawmenu call; avoid flashing
- * 05/18/92 smz return fnfErr from FSDispatch
- * 05/24/92 smz adde cursor rotating code (urp!)
- * 06/04/92 smz add cancelledmenu stuff
- * 06/08/92 smz added Insert && DeleteMenu patches for hierarchial menus
- * 06/11/92 smz added script cancelled stuff, use fsspecs for the collection
- * 06/13/92 smz use Get Info item to determine whether there is any information to collect
- * <1.0 release>
- */
-
- #include <varargs.h>
- #include <stdio.h>
- #include <stddef.h>
- #include <string.h>
- #include <Extension.h>
- #include <Errors.h>
- #include <Patch.h>
- #include <GestaltEqu.h>
- #include <Exceptions.h>
- #include <Traps.h>
- #include <Globals.h>
- #include <AppleEvents.h>
-
- #include <FinderStuff.h>
-
- #include "Utils.h"
- #include "FinderMenuInterface.h"
- #include "MenuList.h"
- #include "DrawstringHack.h"
-
- #include "Patches.h"
-
- #define cDefaultFileMenuID 1252
- #define cContinueAlert 0x177d
- #define cLastAlert 0x177a
-
- #define cNumCursors 4
- #define cFirstCursorID 128
-
- /*
- * Local Globals
- */
- static Boolean theWorldInit;
- static unsigned long theGetInfoItem;
- //static unsigned long theOpenItem;
-
- static short theRunningCount;
-
- static Boolean theFileListGood;
- static AEDescList theFileList;
-
- static Boolean theMenuBarDirty;
-
- static short theDrawingHappening; // for drawstring, stringwidth
-
- static Boolean theInfoValid;
- static FSSpec theInfoFSSpec;
- static OSType theCreator;
-
- static AlertPatch *theAlertPatch;
- static FSDispatchPatch *theFSDispatchPatch;
- static DrawStringPatch *theDrawStringPatch;
- static StringWidthPatch *theStringWidthPatch;
- static SetCursorPatch *theSetCursorPatch;
- static PostEventPatch *thePostEventPatch;
- static ParamTextPatch *theParamTextPatch;
-
- static Boolean theBeachBallRolling = false;
- static Cursor theRollingCursors[cNumCursors];
- static Boolean theCmdPeriodHit;
-
- /***************************************************************************/
-
- static void InitWorld(void)
- {
- GetFinderItem('sinf', cDefaultFileMenuID, &theGetInfoItem);
- // GetFinderItem('sope', cDefaultFileMenuID, &theOpenItem);
- theWorldInit = true;
- }
-
- static Boolean LoadCursors(void)
- {
- reg short i;
-
- for (i = 0; i < cNumCursors; i++) {
- CursHandle hRes = GetCursor(cFirstCursorID + i);
- if (hRes == nil)
- return false;
- theRollingCursors[i] = **hRes;
- ReleaseResource(hRes);
- }
- return true;
- }
-
- static void PushDrawing()
- {
- if (theDrawingHappening++ == 0) {
- theDrawStringPatch->Enable();
- theStringWidthPatch->Enable();
- }
- }
-
- static void PopDrawing()
- {
- if (--theDrawingHappening == 0) {
- theDrawStringPatch->Disable();
- theStringWidthPatch->Disable();
- }
- }
-
- static void StartCursor()
- {
- theBeachBallRolling = true;
- theSetCursorPatch->Enable();
- }
-
- static void EndCursor()
- {
- theBeachBallRolling = false;
- theSetCursorPatch->Disable();
- }
-
- static Cursor *GetNextCursor()
- {
- static short theBeachBallIndex = 0;
- reg Cursor *pCurs = &theRollingCursors[theBeachBallIndex++];
- if (theBeachBallIndex >= cNumCursors)
- theBeachBallIndex = 0;
- return pCurs;
- }
-
- /***************************************************************************/
-
- static Boolean CheckForDialogs()
- {
- if (WindowList != nil)
- if (WindowList->windowKind == dialogKind)
- return false;
-
- return true;
- }
-
- DrawMenuBarPatch::DrawMenuBarPatch()
- {
- GenericPatch::InitGenericPatch(_DrawMenuBar, 0);
- Install();
- }
-
- void DrawMenuBarPatch::Behavior()
- {
- Disable();
-
- if (IsFinderRunning() && CheckForDialogs()) {
- reg DrawMenuBarProcPtr oldDrawMenuBar = (DrawMenuBarProcPtr) itsOld;
-
- PushDrawing();
-
- InsertAllMenus(true);
-
- #if !__option(a4_globals)
- {
- long oldA5 = SetA5((long) itsFrame->ra5);
- #endif
-
- (*oldDrawMenuBar)();
-
- #if !__option(a4_globals)
- (void) SetA5(oldA5);
- }
- #endif
- AbortTrap();
-
- RemoveAllMenus(true);
-
- PopDrawing();
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- static void ActivateCollection()
- {
- if (theFileListGood) {
- #ifdef DEBUG
- DebugStr("\pnobody got the mail!");
- #endif
- SysBeep(1); // nobody picked up their mail!
- AEDisposeDesc(&theFileList);
- }
- theFileListGood = true;
- theAlertPatch->Enable();
- theFSDispatchPatch->Enable();
- thePostEventPatch->Enable();
- theParamTextPatch->Enable();
- theInfoValid = false;
- theCmdPeriodHit = false;
- StartCursor();
- }
-
-
- static void EndCollection(Boolean successful)
- {
- if (theFileListGood) {
- if (successful)
- SendMenuHitInfo(theCreator, &theFileList);
- else
- DeleteMenuHitInfo(theCreator);
-
- AEDisposeDesc(&theFileList);
-
- EndCursor();
- }
-
- theCreator = 0;
- theFileListGood = false;
- theCmdPeriodHit = false;
-
- theAlertPatch->Disable();
- theFSDispatchPatch->Disable();
-
- // we're trying turning this off when the client finishes
- // thePostEventPatch->Disable(); // remindsmz: turn off at endscript time?
-
- theInfoValid = false;
- }
-
- static long HandleMenuResult(unsigned long result)
- {
- if (! theFileListGood)
- if (OwnedMenuHit(result, &theCreator, &theFileList)) {
- ActivateCollection();
- if (! IsItemEnabled(theGetInfoItem)) {
- EndCollection(true); // nothing to collect!
- return 0;
- }
- return theGetInfoItem;
- }
-
- return result;
- }
-
- /***************************************************************************/
-
- MenuSelectPatch::MenuSelectPatch()
- {
- GenericPatch::InitGenericPatch(_MenuSelect, offsetof(MenuSelectParameters, itsResult));
- Install();
- }
-
- void MenuSelectPatch::Behavior()
- {
- Disable();
-
- if (IsFinderRunning() && CheckForDialogs()) {
- reg MenuSelectParameters* params = (MenuSelectParameters*) itsFrame->parameters;
- reg MenuSelectProcPtr oldMenuSelect = (MenuSelectProcPtr) itsOld;
-
- PushDrawing();
-
- InsertAllMenus(false);
-
- {
- #if !__option(a4_globals)
- long oldA5 = SetA5((long) itsFrame->ra5);
- #endif
-
- params->itsResult = (*oldMenuSelect)(params->itsStartPt);
-
- #if !__option(a4_globals)
- (void) SetA5(oldA5);
- #endif
- }
-
- params->itsResult = HandleMenuResult(params->itsResult);
-
- AbortTrap();
-
- RemoveAllMenus(false);
-
- PopDrawing();
- }
-
- Enable();
- }
-
- /****************************************************************************/
-
- MenuKeyPatch::MenuKeyPatch()
- {
- GenericPatch::InitGenericPatch(_MenuKey, offsetof(MenuKeyParameters, itsResult));
- Install();
- }
-
- void MenuKeyPatch::Behavior()
- {
- Disable();
-
- if (IsFinderRunning() && CheckForDialogs()) {
- reg MenuKeyParameters* params = (MenuKeyParameters*) itsFrame->parameters;
- reg MenuKeyProcPtr oldMenuKey = (MenuKeyProcPtr) itsOld;
-
- PushDrawing();
-
- InsertAllMenus(false);
-
- {
- #if !__option(a4_globals)
- long oldA5 = SetA5((long) itsFrame->ra5);
- #endif
- params->itsResult = (*oldMenuKey)(params->itsKey);
-
- #if !__option(a4_globals)
- (void) SetA5(oldA5);
- #endif
- }
-
- params->itsResult = HandleMenuResult(params->itsResult);
-
- AbortTrap();
-
- RemoveAllMenus(false);
-
- PopDrawing();
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- FSDispatchPatch::FSDispatchPatch()
- {
- GenericPatch::InitGenericPatch(0xa260, 0);
- Install();
- Disable();
- }
-
- void FSDispatchPatch::Behavior()
- {
- Disable();
-
- if (theFileListGood
- && (itsFrame->rd0 == 9L)
- && ((itsFrame->rd1 & 0xffff) == 0xa260L)
- && IsFinderRunning()) {
- reg FSDispatchProcPtr oldFSDispatch = (FSDispatchProcPtr) itsOld;
- reg PatchFrame *frame = itsFrame;
-
- /* need to save lots of registers around this OSTrap */
- asm {
- movem.l frame->rd0,d0-d2/a0-a1
- movem.l d3-d7/a2-a5,-(sp)
- }
-
- (*oldFSDispatch)();
-
- asm {
- movem.l (sp)+,d3-d7/a2-a5
- movem.l d0-d2/a0-a1,frame->rd0
- }
-
- AbortTrap();
-
- #define fpb ((HFileInfo*) frame->ra0)
- #define dpb ((DirInfo*) frame->ra0)
-
- if (fpb->ioNamePtr != nil)
- if (fpb->ioNamePtr[0] != 0) {
- itsFrame->rd0 = fnfErr; // cause an error, hence an alert
-
- theInfoFSSpec.vRefNum = fpb->ioVRefNum;
- theInfoFSSpec.parID = dpb->ioDrParID;
- copystring(fpb->ioNamePtr, theInfoFSSpec.name);
-
- theInfoValid = true;
- }
- #undef fpb
- #undef dpb
- }
- if (! theInfoValid)
- Enable();
- }
-
- /***************************************************************************/
-
- void AlertPatch::AlertPatch()
- {
- GenericPatch::InitGenericPatch(_Alert, offsetof(AlertPatchParameters, itsResult));
- Install();
- }
-
- void AlertPatch::Behavior()
- {
- Disable();
-
- if (theFileListGood && IsFinderRunning()) {
- reg AlertPatchParameters *parms = (AlertPatchParameters*) itsFrame->parameters;
-
- if (theInfoValid && ! theCmdPeriodHit) {
- AEDesc pathDesc;
-
- theInfoValid = false;
-
- pathDesc.descriptorType = typeFSS;
- if (AEPutPtr(&theFileList, 0, typeFSS, (void*) &theInfoFSSpec, sizeof(theInfoFSSpec)) != noErr)
- theCmdPeriodHit = true;
- }
-
- if (theCmdPeriodHit) {
- EndCollection(false);
- if (parms->itsID == cContinueAlert)
- parms->itsResult = 2; // stop button - no more collection
- InitCursor();
- theMenuBarDirty = true;
- } else if (parms->itsID == cLastAlert) {
- EndCollection(true);
- } else if (parms->itsID == cContinueAlert) {
- theFSDispatchPatch->Enable();
- parms->itsResult = 1; /* hit continue button */
- } else {
- #ifdef DEBUG
- DebugStr("\pSomething strange in the Finder; don't use FinderMenus!!.");
- #endif
- EndCollection(false);
- }
-
- AbortTrap();
- }
- Enable();
- }
-
- /***************************************************************************/
-
- void NewWindowPatch::NewWindowPatch()
- {
- GenericPatch::InitGenericPatch(_NewWindow, offsetof(NewWindowParameters, itsResult));
- Install();
- }
-
- void NewWindowPatch::Behavior()
- {
- if (theFileListGood && IsFinderRunning()) {
- reg NewWindowParameters *parms = (NewWindowParameters*) itsFrame->parameters;
- parms->itsResult = nil;
- AbortTrap();
- }
- }
-
- void NewCWindowPatch::NewCWindowPatch()
- {
- GenericPatch::InitGenericPatch(_NewCWindow, offsetof(NewWindowParameters, itsResult));
- Install();
- }
-
- void NewCWindowPatch::Behavior()
- {
- if (theFileListGood && IsFinderRunning()) {
- reg NewWindowParameters *parms = (NewWindowParameters*) itsFrame->parameters;
- parms->itsResult = nil;
- AbortTrap();
- }
- }
-
- /***************************************************************************/
-
- void SystemTaskPatch::SystemTaskPatch()
- {
- GenericPatch::InitGenericPatch(_SystemTask, 0);
- Install();
- }
-
- void SystemTaskPatch::Behavior()
- {
- Disable();
-
- if (IsFinderRunning()) {
- Boolean finderIsFront = GetFrontProcessCreator() == 'MACS';
-
- if (theCmdPeriodHit) {
- theCmdPeriodHit = false;
-
- if (theCreator != 0)
- SendCancelledEvent(theCreator);
- }
-
- if (theMenuBarDirty && finderIsFront) {
- theMenuBarDirty = false;
- HiliteMenu(0);
- DrawMenuBar();
- }
-
- if (theBeachBallRolling) {
- if (finderIsFront) {
- theSetCursorPatch->Disable();
- SetCursor(GetNextCursor());
- theSetCursorPatch->Enable();
- } else {
- EndCursor();
- // InitCursor(); REMINDSMZ: switching back to Finder?
- }
- }
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- DrawStringPatch::DrawStringPatch()
- {
- GenericPatch::InitGenericPatch(_DrawString, offsetof(DrawStringParameters, bogusResult));
- Install();
- Disable();
- }
-
- void DrawStringPatch::Behavior()
- {
- Disable();
-
- if (theDrawingHappening > 0) {
- reg DrawStringParameters* params = (DrawStringParameters*) itsFrame->parameters;
-
- if (IsSpecialString(params->itsString)) {
- DrawSpecialString(params->itsString);
- AbortTrap();
- }
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- StringWidthPatch::StringWidthPatch()
- {
- GenericPatch::InitGenericPatch(_StringWidth, offsetof(StringWidthParameters, itsResult));
- Install();
- Disable();
- }
-
- void StringWidthPatch::Behavior()
- {
- Disable();
-
- if (theDrawingHappening > 0) {
- reg StringWidthParameters* params = (StringWidthParameters*) itsFrame->parameters;
- if (IsSpecialString(params->itsString)) {
- params->itsResult = SpecialStringWidth(params->itsString);
- AbortTrap();
- }
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- SetCursorPatch::SetCursorPatch()
- {
- GenericPatch::InitGenericPatch(_SetCursor, offsetof(SetCursorParameters, dummy));
- Install();
- Disable();
- }
-
- void SetCursorPatch::Behavior()
- {
- Disable();
-
- if (theBeachBallRolling && IsFinderRunning())
- AbortTrap();
-
- Enable();
- }
-
- /***************************************************************************/
-
- ParamTextPatch::ParamTextPatch()
- {
- GenericPatch::InitGenericPatch(_ParamText, offsetof(ParamTextParameters, dummy));
- Install();
- Disable();
- }
-
- void ParamTextPatch::Behavior()
- {
- Disable();
-
- if (theFileListGood && IsFinderRunning()) {
- reg ParamTextProcPtr oldParamText = (ParamTextProcPtr) itsOld;
-
- (*oldParamText)(nil, nil, nil, nil);
-
- AbortTrap();
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- PostEventPatch::PostEventPatch()
- {
- GenericPatch::InitGenericPatch(_PostEvent, 0);
- Install();
- Disable();
- }
-
- short keys[] : 0x174;
-
- void PostEventPatch::Behavior()
- {
- Disable();
-
- switch ((short) itsFrame->ra0) {
- case keyDown:
- if ((keys[3] & 0x8000) != 0)
- if ((itsFrame->rd0 & 0x00ff) == '.') {
- theCmdPeriodHit = true;
- AbortTrap();
- }
- break;
- }
-
- Enable();
- }
-
- /***************************************************************************/
-
- static long DoDispatch(short selector, OSType creator, int va_alist)
- {
- va_list args;
- long rVal;
- long tmp0;
- long tmp1;
-
- OpenGlobals();
-
- if (! theWorldInit)
- InitWorld();
-
- switch (selector) {
- case eInitFinderMenu:
- rVal = (long) DoInit(creator);
- break;
- case eAppendMenu:
- va_start(args);
- tmp0 = (long) va_arg(args, MenuHandle);
- tmp1 = (long) va_arg(args, short);
- rVal = (long) DoAppend(creator, (MenuHandle) tmp0, (short) tmp1);
- va_end(args);
- break;
- case eDeleteMenus:
- rVal = (long) DoDelete(creator);
- break;
- case eRemoveEntry:
- rVal = (long) DoRemove(creator);
- break;
- case eClientFinished:
- (void) DoClientDone(creator);
- thePostEventPatch->Disable(); // turning off now
- theParamTextPatch->Disable();
- /* fall through to FreshMenubar */
- case eFreshMenuBar: // maybe next SystemTask…
- theMenuBarDirty = true;
- EndCursor();
- rVal = true;
- break;
- case eRollBeachball:
- StartCursor();
- rVal = false;
- break;
- default: {
- #ifdef DEBUG
- static char s[] = "\pX: selected!";
- s[1] = 0x30 + selector;
- DebugStr(s);
- rVal = 0;
- #endif
- } break;
- }
-
- CloseGlobals();
- return rVal;
- }
-
- #if __option(a4_globals)
-
- static pascal OSErr GestaltFunction(OSType selector, long *response)
- {
- OpenGlobals();
- *response = (long) DoDispatch;
- CloseGlobals();
- return noErr;
- }
-
- static Boolean InstallDispatcher(void)
- {
- RememberGlobals();
- if (NewGestalt(cGetFinderMenuProc, (ProcPtr) StripAddress(GestaltFunction)) != noErr) {
- #ifdef DEBUG
- DebugStr("\pno gestalt!");
- #endif
- return false;
- }
- return true;
- }
-
- #else
-
- struct Dummy {
- long x0;
- long x1;
- short x2;
- long address;
- long x4;
- } dummyProc = {
- // 0xa9ff225f, _Debugger
- 0x4e71225f,
- 0x205f201f,
- 0x20bc,
- 0x00000000,
- 0x42574ed1
- };
-
- static Boolean InstallDispatcher(void)
- {
- reg struct Dummy *newProc = (struct Dummy *) NewPtrSys(sizeof(dummyProc));
- ProcPtr oldToss;
-
- RememberGlobals();
-
- BlockMove(&dummyProc, newProc, sizeof(dummyProc));
- newProc->address = (long) DoDispatch;
-
- if (NewGestalt(cGetFinderMenuProc, newProc) != noErr)
- if (ReplaceGestalt(cGetFinderMenuProc, newProc, &oldToss) != noErr) {
- DebugStr("\pno gestalt!");
- return false;
- }
- return true;
- }
-
- #endif
-
-
- /***************************************************************************/
-
- void Install()
- {
- #ifdef DEBUG
- if (*(short *) 0x100 != -1)
- DebugStr("\ptrace carefully!");
-
- *(short *) 0x100 = 0x32;
- #endif
-
- try {
- if (! System7Running()
- || ! InstallDispatcher()
- || ! LoadCursors()
- || ! InitPrefsFile()
- ) {
- throw(memFullErr);
- }
-
- new SystemTaskPatch;
- new DrawMenuBarPatch;
- new MenuSelectPatch;
- new MenuKeyPatch;
- new NewWindowPatch;
- new NewCWindowPatch;
-
- theAlertPatch = new AlertPatch;
- theFSDispatchPatch = new FSDispatchPatch;
- theDrawStringPatch = new DrawStringPatch;
- theStringWidthPatch = new StringWidthPatch;
- theSetCursorPatch = new SetCursorPatch;
- thePostEventPatch = new PostEventPatch;
- theParamTextPatch = new ParamTextPatch;
-
- // if extension succeeds, show happy icon.
- ShowIconFamily(128);
- } /* try */
-
- catch {
- // extension failed, show sad icon.
- ShowIconFamily(129);
- throw(theException);
- }
- }
-
- // called when system is shutdown.
-
- void Remove()
- {
- Patch::RemoveAll();
- }
-